home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / HTML / QuickForm / Controller.php < prev    next >
PHP Script  |  2004-10-01  |  15KB  |  498 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4.0                                                      |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Alexey Borzov <avb@php.net>                                 |
  17. // |          Bertrand Mansion <bmansion@mamasam.com>                     |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: Controller.php,v 1.10 2004/10/01 09:48:35 avb Exp $
  21.  
  22. require_once 'HTML/QuickForm/Page.php';
  23.  
  24. /**
  25.  * The class representing a Controller of MVC design pattern.
  26.  * 
  27.  * This class keeps track of pages and (default) action handlers for the form,
  28.  * it manages keeping the form values in session, setting defaults and 
  29.  * constants for the form as a whole and getting its submit values.
  30.  * 
  31.  * Generally you don't need to subclass this.
  32.  *
  33.  * @author  Alexey Borzov <avb@php.net>
  34.  * @package HTML_QuickForm_Controller
  35.  * @version $Revision: 1.10 $
  36.  */
  37. class HTML_QuickForm_Controller
  38. {
  39.    /**
  40.     * Contains the pages (HTML_QuickForm_Page objects) of the miultipage form
  41.     * @var array
  42.     */
  43.     var $_pages = array();
  44.  
  45.    /**
  46.     * Contains the mapping of actions to corresponding HTML_QuickForm_Action objects
  47.     * @var array
  48.     */
  49.     var $_actions = array();
  50.  
  51.    /**
  52.     * Name of the form, used to store the values in session 
  53.     * @var string
  54.     */
  55.     var $_name;
  56.  
  57.    /**
  58.     * Whether the form is modal  
  59.     * @var bool
  60.     */
  61.     var $_modal = true;
  62.  
  63.    /**
  64.     * The action extracted from HTTP request: array('page', 'action')
  65.     * @var array
  66.     */
  67.     var $_actionName = null;
  68.  
  69.    /**
  70.     * Class constructor.
  71.     * 
  72.     * Sets the form name and modal/non-modal behaviuor. Different multipage
  73.     * forms should have different names, as they are used to store form 
  74.     * values in session. Modal forms allow passing to the next page only when
  75.     * all of the previous pages are valid.
  76.     *
  77.     * @access public
  78.     * @param  string  form name
  79.     * @param  bool    whether the form is modal
  80.     */
  81.     function HTML_QuickForm_Controller($name, $modal = true)
  82.     {
  83.         $this->_name  = $name;
  84.         $this->_modal = $modal;
  85.     }
  86.  
  87.  
  88.    /**
  89.     * Returns a reference to a session variable containing the form-page 
  90.     * values and pages' validation status.
  91.     * 
  92.     * This is a "low-level" method, use exportValues() if you want just to
  93.     * get the form's values.
  94.     * 
  95.     * @access public
  96.     * @param  bool      If true, then reset the container: clear all default, constant and submitted values
  97.     * @return array
  98.     */
  99.     function &container($reset = false)
  100.     {
  101.         $name = '_' . $this->_name . '_container';
  102.         if (!isset($_SESSION[$name]) || $reset) {
  103.             $_SESSION[$name] = array(
  104.                 'defaults'  => array(),
  105.                 'constants' => array(),
  106.                 'values'    => array(),
  107.                 'valid'     => array()
  108.             );
  109.         }
  110.         foreach (array_keys($this->_pages) as $pageName) {
  111.             if (!isset($_SESSION[$name]['values'][$pageName])) {
  112.                 $_SESSION[$name]['values'][$pageName] = array();
  113.                 $_SESSION[$name]['valid'][$pageName]  = null;
  114.             }
  115.         }
  116.         return $_SESSION[$name];
  117.     }
  118.  
  119.  
  120.    /**
  121.     * Processes the request.
  122.     *
  123.     * This finds the current page, the current action and passes the action
  124.     * to the page's handle() method.
  125.     *
  126.     * @access public
  127.     */
  128.     function run()
  129.     {
  130.         // the names of the action and page should be saved
  131.         list($page, $action) = $this->_actionName = $this->getActionName();
  132.         return $this->_pages[$page]->handle($action);
  133.     }
  134.  
  135.  
  136.    /**
  137.     * Registers a handler for a specific action.
  138.     *
  139.     * @access public
  140.     * @param  string    name of the action
  141.     * @param  object HTML_QuickForm_Action   the handler for the action
  142.     */
  143.     function addAction($actionName, &$action)
  144.     {
  145.         $this->_actions[$actionName] =& $action;
  146.     }
  147.  
  148.  
  149.    /**
  150.     * Adds a new page to the form
  151.     *
  152.     * @access public
  153.     * @param  object HTML_QuickForm_Page
  154.     */
  155.     function addPage(&$page)
  156.     {
  157.         $page->controller =& $this;
  158.         $this->_pages[$page->getAttribute('id')] =& $page;
  159.     }
  160.  
  161.  
  162.    /**
  163.     * Returns a page
  164.     *
  165.     * @access public
  166.     * @param  string    Name of a page
  167.     * @return object    HTML_QuickForm_Page     A reference to the page
  168.     */
  169.     function &getPage($pageName)
  170.     {
  171.         if (!isset($this->_pages[$pageName])) {
  172.             return PEAR::raiseError('HTML_QuickForm_Controller: Unknown page "' . $pageName . '"');
  173.         }
  174.         return $this->_pages[$pageName];
  175.     }
  176.  
  177.  
  178.    /**
  179.     * Handles an action.
  180.     *
  181.     * This will be called if the page itself does not have a handler
  182.     * to a specific action. The method also loads and uses default handlers
  183.     * for common actions, if specific ones were not added.
  184.     * 
  185.     * @access public
  186.     * @param  object HTML_QuickForm_Page    The page that failed to handle the action
  187.     * @param  string    Name of the action
  188.     */
  189.     function handle(&$page, $actionName)
  190.     {
  191.         if (isset($this->_actions[$actionName])) {
  192.             return $this->_actions[$actionName]->perform($page, $actionName);
  193.         }
  194.         switch ($actionName) {
  195.             case 'next':
  196.             case 'back':
  197.             case 'submit':
  198.             case 'display':
  199.             case 'jump':
  200.                 include_once 'HTML/QuickForm/Action/' . ucfirst($actionName) . '.php';
  201.                 $className = 'HTML_QuickForm_Action_' . $actionName;
  202.                 $this->_actions[$actionName] =& new $className();
  203.                 return $this->_actions[$actionName]->perform($page, $actionName);
  204.                 break;
  205.             default:
  206.                 return PEAR::raiseError('HTML_QuickForm_Controller: Unhandled action "' . $actionName . '" in page "' . $page->getAttribute('id') . '"');
  207.         } // switch
  208.     }
  209.  
  210.  
  211.    /**
  212.     * Checks whether the form is modal.
  213.     * 
  214.     * @access public
  215.     * @return bool
  216.     */
  217.     function isModal()
  218.     {
  219.         return $this->_modal;
  220.     }
  221.  
  222.  
  223.    /**
  224.     * Checks whether the pages of the controller are valid
  225.     * 
  226.     * @access public
  227.     * @param  string    If set, check only the pages before (not including) that page
  228.     * @return bool
  229.     */
  230.     function isValid($pageName = null)
  231.     {
  232.         $data =& $this->container();
  233.         foreach (array_keys($this->_pages) as $key) {
  234.             if (isset($pageName) && $pageName == $key) {
  235.                 return true;
  236.             } elseif (!$data['valid'][$key]) {
  237.                 // We should handle the possible situation when the user has never
  238.                 // seen a page of a non-modal multipage form
  239.                 if (!$this->isModal() && null === $data['valid'][$key]) {
  240.                     $page =& $this->_pages[$key];
  241.                     // Use controller's defaults and constants, if present
  242.                     $this->applyDefaults($key);
  243.                     $page->isFormBuilt() or $page->BuildForm();
  244.                     // We use defaults and constants as if they were submitted
  245.                     $data['values'][$key] = $page->exportValues();
  246.                     $page->loadValues($data['values'][$key]);
  247.                     // Is the page now valid?
  248.                     if (true === ($data['valid'][$key] = $page->validate())) {
  249.                         continue;
  250.                     }
  251.                 }
  252.                 return false;
  253.             }
  254.         }
  255.         return true;
  256.     }
  257.  
  258.  
  259.    /**
  260.     * Returns the name of the page before the given.
  261.     * 
  262.     * @access public
  263.     * @param  string 
  264.     * @return string
  265.     */
  266.     function getPrevName($pageName)
  267.     {
  268.         $prev = null;
  269.         foreach (array_keys($this->_pages) as $key) {
  270.             if ($key == $pageName) {
  271.                 return $prev;
  272.             }
  273.             $prev = $key;
  274.         }
  275.     }
  276.  
  277.  
  278.    /**
  279.     * Returns the name of the page after the given.
  280.     * 
  281.     * @access public
  282.     * @param  string 
  283.     * @return string
  284.     */
  285.     function getNextName($pageName)
  286.     {
  287.         $prev = null;
  288.         foreach (array_keys($this->_pages) as $key) {
  289.             if ($prev == $pageName) {
  290.                 return $key;
  291.             }
  292.             $prev = $key;
  293.         }
  294.         return null;
  295.     }
  296.  
  297.  
  298.    /**
  299.     * Finds the (first) invalid page
  300.     * 
  301.     * @access public
  302.     * @return string  Name of an invalid page
  303.     */
  304.     function findInvalid()
  305.     {
  306.         $data =& $this->container();
  307.         foreach (array_keys($this->_pages) as $key) {
  308.             if (!$data['valid'][$key]) {
  309.                 return $key;
  310.             }
  311.         }
  312.         return null;
  313.     }
  314.  
  315.  
  316.    /**
  317.     * Extracts the names of the current page and the current action from
  318.     * HTTP request data. 
  319.     *
  320.     * @access public
  321.     * @return array     first element is page name, second is action name
  322.     */
  323.     function getActionName()
  324.     {
  325.         if (is_array($this->_actionName)) {
  326.             return $this->_actionName;
  327.         }
  328.         $names = array_map('preg_quote', array_keys($this->_pages));
  329.         $regex = '/^_qf_(' . implode('|', $names) . ')_(.+?)(_x)?$/';
  330.         foreach (array_keys($_REQUEST) as $key) {
  331.             if (preg_match($regex, $key, $matches)) {
  332.                 return array($matches[1], $matches[2]);
  333.             }
  334.         }
  335.         if (isset($_REQUEST['_qf_default'])) {
  336.             $matches = explode(':', $_REQUEST['_qf_default'], 2);
  337.             if (isset($this->_pages[$matches[0]])) {
  338.                 return $matches;
  339.             }
  340.         }
  341.         reset($this->_pages);
  342.         return array(key($this->_pages), 'display');
  343.     }
  344.  
  345.  
  346.    /**
  347.     * Initializes default form values.
  348.     *
  349.     * @access public
  350.     * @param  array  default values
  351.     * @param  mixed  filter(s) to apply to default values
  352.     * @throws PEAR_Error
  353.     */
  354.     function setDefaults($defaultValues = null, $filter = null)
  355.     {
  356.         if (is_array($defaultValues)) {
  357.             $data =& $this->container();
  358.             return $this->_setDefaultsOrConstants($data['defaults'], $defaultValues, $filter);
  359.         }
  360.     }
  361.  
  362.  
  363.    /**
  364.     * Initializes constant form values.
  365.     * These values won't get overridden by POST or GET vars
  366.     *
  367.     * @access public
  368.     * @param  array  constant values
  369.     * @param  mixed  filter(s) to apply to constant values
  370.     * @throws PEAR_Error
  371.     */
  372.     function setConstants($constantValues = null, $filter = null)
  373.     {
  374.         if (is_array($constantValues)) {
  375.             $data =& $this->container();
  376.             return $this->_setDefaultsOrConstants($data['constants'], $constantValues, $filter);
  377.         }
  378.     }
  379.  
  380.  
  381.    /**
  382.     * Adds new values to defaults or constants array
  383.     *
  384.     * @access   private
  385.     * @param    array   array to add values to (either defaults or constants)
  386.     * @param    array   values to add
  387.     * @param    mixed   filters to apply to new values
  388.     * @throws   PEAR_Error
  389.     */
  390.     function _setDefaultsOrConstants(&$values, $newValues, $filter = null)
  391.     {
  392.         if (isset($filter)) {
  393.             if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
  394.                 foreach ($filter as $val) {
  395.                     if (!is_callable($val)) {
  396.                         return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm_Controller::_setDefaultsOrConstants()", 'HTML_QuickForm_Error', true);
  397.                     } else {
  398.                         $newValues = $this->_arrayMapRecursive($val, $newValues);
  399.                     }
  400.                 }
  401.             } elseif (!is_callable($filter)) {
  402.                 return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm_Controller::_setDefaultsOrConstants()", 'HTML_QuickForm_Error', true);
  403.             } else {
  404.                 $newValues = $this->_arrayMapRecursive($val, $newValues);
  405.             }
  406.         }
  407.         $values = HTML_QuickForm::arrayMerge($values, $newValues);
  408.     }
  409.  
  410.  
  411.    /**
  412.     * Recursively applies the callback function to the value
  413.     * 
  414.     * @param    mixed   Callback function
  415.     * @param    mixed   Value to process
  416.     * @access   private
  417.     * @return   mixed   Processed values
  418.     */
  419.     function _arrayMapRecursive($callback, $value)
  420.     {
  421.         if (!is_array($value)) {
  422.             return call_user_func($callback, $value);
  423.         } else {
  424.             $map = array();
  425.             foreach ($value as $k => $v) {
  426.                 $map[$k] = $this->_arrayMapRecursive($callback, $v);
  427.             }
  428.             return $map;
  429.         }
  430.     }
  431.  
  432.  
  433.    /**
  434.     * Sets the default values for the given page
  435.     *
  436.     * @access public
  437.     * @param  string  Name of a page
  438.     */
  439.     function applyDefaults($pageName)
  440.     {
  441.         $data =& $this->container();
  442.         if (!empty($data['defaults'])) {
  443.             $this->_pages[$pageName]->setDefaults($data['defaults']);
  444.         }
  445.         if (!empty($data['constants'])) {
  446.             $this->_pages[$pageName]->setConstants($data['constants']);
  447.         }
  448.     }
  449.  
  450.  
  451.    /**
  452.     * Returns the form's values
  453.     * 
  454.     * @access public
  455.     * @param  string    name of the page, if not set then returns values for all pages
  456.     * @return array
  457.     */
  458.     function exportValues($pageName = null)
  459.     {
  460.         $data   =& $this->container();
  461.         $values =  array();
  462.         if (isset($pageName)) {
  463.             $pages = array($pageName);
  464.         } else {
  465.             $pages = array_keys($data['values']);
  466.         }
  467.         foreach ($pages as $page) {
  468.             // skip elements representing actions
  469.             foreach ($data['values'][$page] as $key => $value) {
  470.                 if (0 !== strpos($key, '_qf_')) {
  471.                     if (isset($values[$key]) && is_array($value)) {
  472.                         $values[$key] = HTML_QuickForm::arrayMerge($values[$key], $value);
  473.                     } else {
  474.                         $values[$key] = $value;
  475.                     }
  476.                 }
  477.             }
  478.         }
  479.         return $values;
  480.     }
  481.  
  482.  
  483.    /**
  484.     * Returns the element's value
  485.     * 
  486.     * @access public
  487.     * @param  string    name of the page
  488.     * @param  string    name of the element in the page
  489.     * @return mixed     value for the element
  490.     */
  491.     function exportValue($pageName, $elementName)
  492.     {
  493.         $data =& $this->container();
  494.         return isset($data['values'][$pageName][$elementName])? $data['values'][$pageName][$elementName]: null;
  495.     }
  496. }
  497. ?>
  498.